# @Version        : 1.0
# @Update Time    : 2024/9/21 11:11
# @File           : user_service.py
# @IDE            : PyCharm
# @Desc           : 用户业务
import json

from advanced_alchemy import service
from sqlalchemy import or_, and_
from typing import List, Dict, Any

from authx.core.auth_util import AuthUtil
from authx.models.session import SessionKey, TerminalInfoModel
from src import schemas, models
from src.core.exception import BaseAppException
from src.log import logger
from src.crud.post_repository import PostRepo
from src.crud.role_repository import RoleRepo
from src.crud.user_repository import UserRepository


class UserService(
    service.SQLAlchemyAsyncRepositoryService[models.SysUser, UserRepository]
):
    repository_type = UserRepository

    # loader_options = [models.RaUser.posts, models.RaUser.roles]

    async def create_user(self, data: schemas.UserCreate) -> models.SysUser:
        data.password = models.SysUser.get_password_hash(data.password)
        where = [
            models.SysUser.username == data.username,
        ]
        res = await super().list(or_(*where))
        if res:
            raise BaseAppException(msg=f"用户名已存在：{data.username}")
        else:
            user_dict = data.model_dump(exclude={"post_ids", "role_ids"})
            logger.info(f"用户信息：{data.post_ids}{data.role_ids}")
            model = models.SysUser(**user_dict)
            if data.post_ids:
                posts = await PostRepo(session=self.repository.session).list(
                    and_(models.SysPost.id.in_(data.post_ids))
                )
                model.posts.add(*posts)
            if data.role_ids:
                roles = await RoleRepo(session=self.repository.session).list(
                    and_(models.SysRole.id.in_(data.role_ids))
                )
                model.roles.add(*roles)
            logger.warning(f"用户信息：{model.to_dict()}")
            user = await super().create(model, auto_commit=True)
            return user

    async def update_user(self, data: schemas.UserUpdate) -> None:
        # 判断修改的邮箱、手机号是否已存在
        user_dict = data.model_dump(exclude={"post_ids", "role_ids"})
        user = await self.get(data.id, load=[models.SysUser.posts, models.SysUser.roles])
        user.set_attrs(user_dict)
        posts = await PostRepo(session=self.repository.session).list(
            and_(models.SysPost.id.in_(data.post_ids))
        )
        user.posts = set(posts)
        roles = await RoleRepo(session=self.repository.session).list(
            and_(models.SysRole.id.in_(data.role_ids))
        )
        user.roles = set(roles)
        await self.repository.session.commit()

    async def get_online_users(self) -> List[Dict[str, Any]]:
        """
        获取所有在线用户基本信息（用于树状表格第一层）
        返回格式：[{用户基本信息, device_count, is_online}]
        不包含角色、部门、岗位等信息
        """
        # 按用户ID分组存储在线会话信息
        users_map = {}
        # 用于跟踪已处理的token，避免重复
        processed_tokens = set()
        try:
            # 搜索所有有效的token会话ID
            token_session_ids = await AuthUtil.search_token_session_id(
                keyword=None, start=0, size=1000
            )

            for token_session_id in token_session_ids:
                try:
                    token_value = token_session_id

                    # 避免重复处理
                    if token_value in processed_tokens:
                        continue
                    processed_tokens.add(token_value)

                    # 获取登录ID
                    login_id = await AuthUtil.get_login_id_by_token(token_value)
                    if not login_id:
                        continue

                    # 获取token会话信息
                    token_session = await AuthUtil.get_token_session_by_token(
                        token_value
                    )
                    if not token_session:
                        continue

                    # 如果用户ID不在映射中，查询用户信息并初始化
                    if login_id not in users_map:
                        # 根据登录ID获取用户信息
                        user = token_session.get(SessionKey.USER.value)
                        if not user:
                            continue
                        # 判断是否dict
                        if not isinstance(user, dict):
                            # 字符串转为字典
                            user = json.loads(user)
                        user["device_count"] = 0
                        users_map[login_id] = user

                    # 增加设备计数
                    users_map[login_id]["device_count"] += 1

                except Exception as e:
                    logger.error(f"处理单个用户信息失败: {str(e)}")
                    continue

            # 转换为列表格式
            online_users = list(users_map.values())

            # 如果通过token_session_id方式获取不到数据，尝试使用另一种方式
            if not online_users:
                # 搜索所有会话ID
                session_ids = await AuthUtil.search_session_id(
                    keyword=None, start=0, size=1000
                )

                for session_id in session_ids:
                    try:
                        # 获取会话信息
                        session = await AuthUtil.get_session_by_session_id(session_id)
                        if not session or not hasattr(session, "login_id"):
                            continue

                        login_id = session.login_id
                        # 获取所有token值
                        token_values = await AuthUtil.get_token_value_list_by_login_id(
                            login_id
                        )

                        # 更新设备计数
                        if login_id in users_map:
                            users_map[login_id]["device_count"] += len(
                                [t for t in token_values if t not in processed_tokens]
                            )
                        else:
                            # 根据登录ID获取用户信息
                            user = session.get(SessionKey.USER.value)
                            if not user:
                                continue
                            if not isinstance(user, dict):
                                # 字符串转为字典
                                user = json.loads(user)
                            # 构建用户信息（只包含基本信息，不包含角色、部门、岗位等）
                            user["device_count"] = len(token_values)
                            users_map[login_id] = user

                        # 更新已处理的token
                        processed_tokens.update(token_values)

                    except Exception as e:
                        logger.error(f"通过会话ID处理在线用户信息失败: {str(e)}")
                        continue

                # 转换为列表格式
                online_users = list(users_map.values())

        except Exception as e:
            logger.error(f"获取在线用户列表失败: {str(e)}")
            online_users = []

        return online_users

    async def get_user_devices(self, user_id: int) -> List[TerminalInfoModel]:
        """
        获取指定用户的所有登录设备信息
        """
        try:
            # 获取用户所有的token值
            terminals = await AuthUtil.get_terminal_list_by_login_id(str(user_id))
            return terminals
        except Exception as e:
            logger.error(f"获取用户设备列表失败: {str(e)}")

        return []
